public class Main {
    public static void main(String[] args) {
        //3. StringBuilder和StringBuffer
        //由于String的不可更改特性，为了方便字符串的修改，Java中又提供StringBuilder和StringBuffer类。这两个类大
        //部分功能是相同的，这里介绍 StringBuilder常用的一些方法，其它需要用到了大家可参阅
        //StringBuilder在线文档

        StringBuilder sb1 = new StringBuilder("hello");
        StringBuilder sb2 = sb1;
        StringBuffer stringBuffer = new StringBuffer("abc");
        // 追加：即尾插-->字符、字符串、整形数字
        sb1.append(' ');                  // hello
        sb1.append("world");              // hello world
        sb1.append(123);                  // hello world123
        System.out.println(sb1);          // hello world123
        System.out.println(sb1 == sb2);   // true
        System.out.println(sb1.charAt(0));   // 获取0号位上的字符  h
        System.out.println(sb1.length());    // 获取字符串的有效长度14
        System.out.println(sb1.capacity());  // 获取底层数组的总大小
        sb1.setCharAt(0, 'H');     // 设置任意位置的字符 Hello world123
        sb1.insert(0, "Hello world!!!");         // Hello world!!!Hello world123
        System.out.println(sb1);
        System.out.println(sb1.indexOf("Hello"));          // 获取Hello第一次出现的位置
        System.out.println(sb1.lastIndexOf("hello"));  // 获取hello最后一次出现的位置
        sb1.deleteCharAt(0);                               // 删除首字符
        sb1.delete(0,5);                                   // 删除[0, 5)范围内的字符

        String str = sb1.substring(0, 5);                  // 截取[0, 5)区间中的字符以String的方式返回
        System.out.println(str);
        sb1.reverse();                      // 字符串逆转
        str = sb1.toString();               // 将StringBuffer以String的方式返回
        System.out.println(str);
        //从上述例子可以看出：String和StringBuilder最大的区别在于String的内容无法修改，而StringBuilder的内容可
        //以修改。频繁修改字符串的情况考虑使用StringBuilder。
        //注意：String和StringBuilder类不能直接转换。如果要想互相转换，可以采用如下原则:
        // String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
        //StringBuilder变为String: 调用toString()方法。

        //3.2 面试题：
        //1. String、StringBuffer、StringBuilder的区别
        //String的内容不可修改，StringBuffer与StringBuilder的内容可以修改.
        //两者包含的方法也不一样
        // StringBuffer与StringBuilder大部分功能是相似的
        //StringBuffer采用同步处理，属于线程安全操作；而StringBuilder未采用同步处理，属于线程不安全操
        //作
        //因为StringBuffer里面的所有方法被synchronized修饰，这个修饰是表示安全的
        // 而StringBuilder里面没有这个修饰
        // 这两个里面包含了String本身没有的类
        //2. 以下总共创建了多少个String对象【前提不考虑常量池之前是否存在】
        ///String str = new String("ab");   // 会创建多少个对象
        // 两个对象
        // “” 引起来的是一个字符串对象 ， new一个的又是新的一个对象
        //String str = new String("a") + new String("b");  // 会创建多少个对象
        // 一共有六个对象（包括其他的对象）
        // “ ” 引起来的是一个字符串对象 ， new一个的又是新的一个对象
        // 而 + 拼接又会引出来一个StringBuilder 对象 而 再将其赋值给str又会引出来 toString() 对象
        // 而 一共有 五个String对象 ，不算StringBuilder·
    }
    public static void main10(String[] args) {
        //2.10 字符串修改
        //String在进行拼接的时候会产生一个新的类StringBuffer
        // 在通过StringBuffer里面的toString方法才能调用，这也是一个新的方法
        //注意：尽量避免直接对String类型对象进行修改，因为String类是不能修改的，所有的修改都会创建新对象，效率
        //非常低下。
        long start = System.currentTimeMillis();
        String s = "";
        for(int i = 0; i < 10000; ++i){
            s += i;
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);

        start = System.currentTimeMillis();
        StringBuffer sbf = new StringBuffer("");
        for(int i = 0; i < 10000; ++i){
            sbf.append(i);
        }
        end = System.currentTimeMillis();
        System.out.println(end - start);

        start = System.currentTimeMillis();
        StringBuilder sbd = new StringBuilder();
        for(int i = 0; i < 10000; ++i){
            sbd.append(i);
        }
        end = System.currentTimeMillis();
        System.out.println(end - start);
        //可以看待在对String类进行修改时，效率是非常慢的，因此：尽量避免对String的直接需要，如果要修改建议尽量
        //使用StringBuffer或者StringBuilder。
        //b. 借助StringBuffer 和 StringBuilder
    }
    public static void main9(String[] args) {
        //2.9 字符串的不可变性
        //双引号 引起来的值 就存在字符串常量池当中。如果有，就不存储，直接返回字符串常量池中的对象即可。

        //String是一种不可变对象. 字符串中的内容是不可改变。字符串不可被修改，是因为：
        // 最主要是因为里面的数组有private修饰
        //1. String类在设计时就是不可改变的，String类实现描述中已经说明了
        //1. String类被final修饰，表明该类不能被继承
        //2. value被修饰被final修饰，表明value自身的值不能改变，即不能引用其它字符数组，但是其引用空间中
        //的内容可以修改。

        //2. 所有涉及到可能修改字符串内容的操作都是创建一个新对象，改变的是新对象
        //final修饰类表明该类不想被继承，final修饰引用类型表明该引用变量不能引用其他对象，但是其引用对象中的内
        //容是可以修改的。

        //为什么 String 要设计成不可变的?(不可变对象的好处是什么?) (选学)
        // 1. 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑写时拷贝的问题了.
        //2. 不可变对象是线程安全的.
        //3. 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中.

    }
    public static void main8(String[] args) {
        //2.8 其他操作方法
        //方法
        //String trim() 去掉字符串中的左右空格,保留中间空格，删除两边空格
        //String toUpperCase() 字符串转大写
        //String toLowerCase() 字符串转小写
        //代码示例: 观察trim()方法的使用
        String str = "   hello  world   " ;
        System.out.println("["+str+"]");
        System.out.println("["+str.trim()+"]");
        //trim 会去掉字符串开头和结尾的空白字符(空格, 换行, 制表符等).
        //去掉字符串左右两边的空格，中间的空格无法去掉 .trim()

    }
    public static void main7(String[] args) {
        //2.7 字符串截取
        //方法
        //String substring(int beginIndex) 从指定索引截取到结尾
        //String substring(int beginIndex, int endIndex)  截取部分内容

        //代码示例: 观察字符串截取
        String str = "helloworld" ;
        System.out.println(str.substring(5));//返回从5位置开始截取的所有字符
        System.out.println(str.substring(0, 5));//截取0位置到5位置的区间不包括5位置
        //注意事项:
        //1. 索引从0开始
        //2. 注意 前闭后开区间 的写法, substring(0, 5) 表示包含 0 号下标的字符, 不包含 5 号下标

    }
    public static void main6(String[] args) {
        //2.6 字符串拆分
        //可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串。
        //方法
        //String[] split(String regex) //将字符串全部拆分
        //String[] split(String regex, int limit) //将字符串以指定的格式，拆分为limit组

        //代码示例: 实现字符串的拆分处理

        String str = "hello world hello bit" ;
        String[] result = str.split(" ") ; // 按照空格拆分
        for(String s: result) {
            System.out.println(s);
        }
        //代码示例: 字符串的部分拆分
        String str1 = "hello world hello bit" ;
        String[] result1 = str1.split(" ",2) ;
        for(String s: result1) {
            System.out.println(s);
        }
        //拆分是特别常用的操作. 一定要重点掌握. 另外有些特殊字符作为分割符可能无法正确切分, 需要加上转义.

        //代码示例: 拆分IP地址
        String str3 = "192.168.1.1" ;
        String[] result3 = str3.split("\\.") ;
        for(String s: result3) {
            System.out.println(s);
        }
        //注意事项:
        // 1. 字符"|","*","+"都得加上转义字符，前面加上"\\".必须要注意4
        // 2. 而如果是"\"，那么就得写成"\\\\".
        // 3. 如果一个字符串中有多个分隔符，可以用"|"作为连字符.

        //代码示例: 多次拆分
        String str6 = "helloworld" ;
        System.out.println(str6.substring(5));
        System.out.println(str6.substring(0, 5));
        //注意事项:
        // 1. 索引从0开始
        //2. 注意前闭后开区间的写法, substring(0, 5) 表示包含 0 号下标的字符, 不包含 5 号下标

    }
    public static void main5(String[] args) {
        //2.5 字符串替换
        //使用一个指定的新的字符串替换掉已有的字符串数据，可用的方法如下：
        //方法
        //String replaceAll(String regex, String replacement)  //替换所有的指定内容
        //String replaceFirst(String regex, String replacement) //替换首个内容
        String str = "helloworld" ;
        System.out.println(str.replace("he","000"));
        System.out.println(str.replaceAll("l", "_"));
        System.out.println(str.replaceFirst("l", "_"));
        //注意事项: 由于字符串是不可变对象, 替换不修改当前字符串, 而是产生一个新的字符串.产生的是一个新的对象
        //如果传字符串就是向上转型

    }
    public static void main4(String[] args) {
        //2.4 转化
        //1. 数值和字符串转化
        String str2 =  String.valueOf(123);
        System.out.println(str2);
        String s1 = String.valueOf(1234);
        String s2 = String.valueOf(12.34);
        String s3 = String.valueOf(true);
       // String s4 = String.valueOf(new Student("Hanmeimei", 18));
        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s3);
       // System.out.println(s4);
        System.out.println("=================================");
        // // 字符串转数字
        int data1 = Integer.parseInt("1234");//有类名来直接调用的
        //基本类型对应的类类型 所以 基本类型也提供了面向对象的思想

        double data2 = Double.parseDouble("12.34");
        System.out.println(data1);
        System.out.println(data2);


        //2. 大小写转换
        String s11 = "hello";
        String s22 = "HELLO";
        // 小写转大写
        System.out.println(s11.toUpperCase());
        // 大写转小写
        System.out.println(s22.toLowerCase());

        //3. 字符串转数组
        String s = "hello";
        // 字符串转数组
        char[] ch = s.toCharArray();
        for (int i = 0; i < ch.length; i++) {
            System.out.print(ch[i]);
        }
        System.out.println();
        // 数组转字符串
        String s5 = new String(ch);
        System.out.println(s5);

        //4. 格式化
        String t = String.format("%d-%d-%d", 2019, 9,14);
        System.out.println(t);
    }
    public static void main3(String[] args) {
        //2.3 字符串查找
        String s = "aaabbbcccaaabbbccc";
        System.out.println(s.charAt(3));                             // 'b'
        System.out.println(s.indexOf('c'));                         // 6
        System.out.println(s.indexOf('c', 10));                      // 15
        System.out.println(s.indexOf("bbb"));                        // 3
        System.out.println(s.indexOf("bbb", 10));                    // 12
        System.out.println(s.lastIndexOf('c'));                      // 17
        System.out.println(s.lastIndexOf('c', 10));                  // 8
        System.out.println(s.lastIndexOf("bbb"));                    // 12
        System.out.println(s.lastIndexOf("bbb", 10));                // 3
    }
    public static void main2(String[] args) {
        //字符串的比较
        //1. ==比较是否引用同一个对象
        //对于内置类型，==比较的是变量中的值；对于引用类型==比较的是引用中的地址。

        //boolean equals(Object anObject)方法：按照字典序比较
        // .equals()


        //3. int compareTo(String s)方法: 按照字典序进行比较
        //字符串大小的比较
        String str1 = "helloabc";
        String str2 = "hello";
        System.out.println(str1.compareTo(str2));
        System.out.println(str1.compareToIgnoreCase(str2));//忽略大小写的比较
        //注意汉字是没有大小写的
        System.out.println(str1.equalsIgnoreCase(str2)); //忽略大小写的判断相等

    }
    public static void main1(String[] args) {
       char[] values = {'a','b','c','d'};
       //把字符数组变成字符串
        String str = new String(values);
        System.out.println(str);
        //求字符串的长度和判断字符串是否为空
        String str1="";
        System.out.println(str1.length());
        System.out.println(str1.isEmpty());
        String str3 = null;
        //str2 和 str3 两者的空是完全不一样的。
     }
}